using System;
using System.Collections.Generic;
using System.Text;

namespace GeneticAlgorithm.DNA
{
    class GeneManager2
    {
        /// This class manages what would be managed by lisp trees.  It keeps track of some base-case actions,
        /// as well as nested ones.  Whenever it recieves an instruction, it breaks the instruction down recursively




        /// <summary>
        /// This class will accept a line of instructions and recursively perform a depth-first traversl of the instructions
        /// It is important that the instructions end in a constant.  That is, the last evaluated leaf of the tree must be 
        /// a constant, or else all will be lost.
        /// </summary>
        /// <param name="line"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public float Interpret(string line, params Object[] arguments)
        {

            return (RInterpret(line, arguments));

        }

        private float RInterpret(string line, params Object[] arguements)
        {
            //make sure that line is not null, or else return 0
            int retVal = 0;

            if (line != null)
            {

                float retVal = 0f;

                //Get the first action.  This is the root of our subtree
                String action = line.Substring(0, 1);

                //split the tree acording to the right most leaf of the left most node (a little hardcoding for now)
                int index = 1 + line.IndexOf("C");
                String leftPart = line.Substring(0, index);
                String rightPart;
                //rightPart is the rest (if it isn't going to cause an exception)
                try
                {
                    rightPart = line.Substring(index, line.Length);
                }
                catch (Exception e)
                {
                    //set the right part to null
                    rightPark = null;
                }

                ///The ones dealing with two parameters
                if (action == "A")
                {
                    //do A on recursive evaulation of the rest of the tree
                    retVal = ActionA(RInterpret(leftPart, arguments), RInterpret(rightPart, arguments));
                }
                else if (action == "M")
                {
                    retVal = ActionM(RInterpret(leftPart, arguments), RInterpret(rightPart, arguments));
                }
                else if (action == "S")
                {
                    retVal = ActionS(RInterpret(leftPart, arguments), RInterpret(rightPart, arguments));
                }
                else if (action == "D")
                {
                    retVal = ActionD(RInterpret(leftPart, arguments), RInterpret(rightPart, arguments));
                }
                ///Dealing with a single parameter     
                else if (action == "C")
                {
                    retVal = ActionC();
                }

            }

            return retVal;

        }



        ///These are the actions the program can take.  I've implemented some math functions, such as addition, multiplication
        ///Subraction, and Division.  
        /// 
        /// 
        ///Eventually, I'd like to use all of the math functions available from the class.  I need
        ///to come up with a way to refer to all of the functions in the math class.
        ///


        ///methods accepting two inputs (I may need to use try-catch blocks to detect bad genotypes)
        //add two values to each other
        private float ActionA(float val1, float val2)
        {
            return val1 + val2;
        }
        //multiply these two values
        private float ActionM(float val1, float val2)
        {
            return val1 * val2;
        }
        //subtract the second from the first
        private float ActionS(float val1, float val2)
        {
            return val1 - val2;
        }
        //divide these two values
        private float ActionD(float val1, float val2)
        {
            return val1 / val2;
        }


        //methods accepting one input
        //some will perform another function
        //others will return a constant




        //For now all I will do is set the value to .5 because I need a constant to which to reduce this
        //I need some way of initiating constants based on input.
        private float ActionC()
        {
            return .5;
        }


    }
}